//
// Created by whg on 2025-06-18.
//

#ifndef PYVM_2025_FUNCTION_OBJECT_HPP
#define PYVM_2025_FUNCTION_OBJECT_HPP


#include "object/pyObject.hpp"
#include "code/codeObject.hpp"
#include "util/map.hpp"

class NativeFunctionKlass: public Klass {
private:
    static NativeFunctionKlass* instance;
    NativeFunctionKlass();

public:
    static NativeFunctionKlass* getInstance();
};

class FunctionKlass: public Klass {
private:
    static FunctionKlass* instance;
    FunctionKlass(){

    }

public:
    static FunctionKlass* getInstance();

    void print(PyObject* obj) override;
};

typedef PyObject* (*NativeFuncPointer)(ObjList args);
PyObject* len(ObjList args);
PyObject* print(ObjList args);

class FunctionObject: public PyObject {
friend class FunctionKlass;
friend class FrameObject;

private:
    CodeObject* _funcCode = nullptr;
    PyString* _funcName = nullptr;
    Map<PyObject*, PyObject*>* _globals = nullptr;
    ObjList _defaults = nullptr;
    NativeFuncPointer _nativeFunc = nullptr;

public:
    FunctionObject(PyObject* codeObj);
    FunctionObject(Klass* klass){
        setKlass(klass);
    }
    FunctionObject(NativeFuncPointer nativeFunc){
        _nativeFunc = nativeFunc;
        setKlass(NativeFunctionKlass::getInstance());
    }

    PyString* funcName(){
        return _funcName;
    }
    void setGlobals(Map<PyObject*, PyObject*>* globals){
        _globals = globals;
    }
    void setDefaults(ObjList defaults);

    PyObject* call(ObjList args);
};

class MethodKlass: public Klass {
private:
    static MethodKlass* instance;
    MethodKlass();

public:
    static MethodKlass* getInstance();
};

class MethodObject: public PyObject {
friend class MethodKlass;

private:
    PyObject* _owner;
    FunctionObject* _func;

public:
    MethodObject(FunctionObject* func) : _owner(nullptr), _func(func){
        setKlass(MethodKlass::getInstance());
    }
    MethodObject(FunctionObject* func, PyObject* owner): _owner(owner), _func(func){
        setKlass(MethodKlass::getInstance());
    }

    void setOwner(PyObject* owner){
        _owner = owner;
    }
    PyObject* owner(){
        return _owner;
    }
    FunctionObject* func(){
        return _func;
    }

    static bool isFunction(PyObject* obj);
    static bool isMethod(PyObject* obj);
};

#endif //PYVM_2025_FUNCTION_OBJECT_HPP
